28. Do not Return Handle for inner Object

class Point{
public:
Point(int x, int y);
// ...
void setX(int newVal);
void setY(int newVal);
// ...
private:
int x, y;
};
struct RectData{
Point ulhc; // Upper Left-Hand Corner
Point lrhc; // Lower Right-Hand Corner
};
class Rectangle{
Point& upperLeft(void) const{ return pData->ulhc; }
Point& lowerRight(void) const{ return pData->lrhc; }
// ...
private:
std::shared_ptr<RectData> pData;
};
위에 코드에서 upperLeft와 lowerRight에 대한 변경을 막기 위해 const member로 upperLeft와 lowerRight를
정의했다.
하지만, 레퍼런스(포인터)로 값을 반환했기 때문에 사용자는 해당 참조자의 내부 데이터를 맘대로 수정할 수 있다.
Point coord1(0, 0);
Point coord2(100, 100);
const Rectangle rec(coord1, coord2);
// const Rectangle Point .
rec.upperLeft().setX(50);
클래스 데이터 멤버를 참조자로 반환하는 함수들의 최대 접근도에 따라 캡슐화 정도가 정해진다.
ulhc와 lrhc를 private로 지정해도, 참조자를 반환하는 upperLeft및 lowerRight는 public이기에
public처럼 참조자(포인터)가 가르키는 데이터를 변경할 수 있다.

상수 멤버 함수의 참조자 반환 값의 실제 데이터가 객체의 바깥에 저장되어 있을 경우 데이터가 수정 가능하다.

(비트수준 상수성을 만족하지 않음)

외부 공개가 차단된 멤버에 대해, 이들의 포인터를 반환하는 멤버 함수는 만들어서는 안된다.
(멤버 함수 포인터를 반환하는 함수의 접근도에 실질적인 접근 수준이 맞춰진다.)

만일 외부에 레퍼런스(포인터)를 반환하는 멤버함수가 필요한 경우,
반환값을 const로 지정해줌으로써 접근 권한을 제한할 수 있다.
class Rectangle{
public:
// ...
const Point& upperLeft(void) const{ return pData->ulhc; }
const Point& lowerRight(void) const{ return pData->lrhc; }
// ...
}
하지만, 여전히 무효참조 핸들(dangling handle)로서, 핸들을 따라 갔을 때 실제 객체의 데이터가 없을 수 있다.
class GUIObject{ /* ... */ };
const Rectangle boundingBox(const GUIObject& obj);
GUIObject* pgo;
// ... pgo GUIObject
const Point* pUpperLeft=&(boundingBox(*pgo).upperLeft());
boundingBox 함수가 const-value로 리턴한다고 할 때,
pUpperLeft에는 임시 변수에 대한 ulhc의 주소가 저장된다.
하지만, 이 후 temp는 소멸된다. 따라서 pUpperLeft는 빈 주소 값만 가지게 된다.

바깥으로 떨어져 나온 핸들이 참조하는 객체보다 더 오래 살 위험이 있기 때문에
핸들을 반환하는 함수 사용을 지양해야 한다.

컨테이너가 사라질 때, 더 이상 사용하지 못하게 할 때는 위의 특징을 적절히 활용하여 구현할 수 있다.